package x

import (
	"errors"
	"fmt"
	"reflect"
)

func Copy(src interface{}, dst interface{}) (err error) {
	st := reflect.TypeOf(src)
	sv := reflect.ValueOf(src)
	if st.Kind() == reflect.Ptr {
		st = st.Elem()
		sv = reflect.Indirect(sv)
	}
	if st.Kind() != reflect.Struct {
		return errors.New("src must be struct")
	}
	dt := reflect.TypeOf(dst)
	dv := reflect.ValueOf(dst)
	if dt.Kind() == reflect.Ptr {
		dt = dt.Elem()
		dv = reflect.Indirect(dv)
	}
	if dt.Kind() != reflect.Struct {
		return errors.New("src must be struct")
	}
	defer func() {
		r := recover()
		if r != nil {
			err = errors.New(fmt.Sprintf("%v", r))
			return
		}
	}()
	for i := 0; i < st.NumField(); i++ {
		f := st.Field(i)
		to := dv.FieldByName(f.Name)
		fr := sv.Field(i)
		if to.IsValid() {
			_, ok := f.Tag.Lookup("ignore")
			if !ok || ok && !Empty(fr.Interface()) {
				to.Set(fr)
			}
		}
	}

	return nil
}
